package com.mark.web.sys.controller.frontend;

import com.mark.common.ServerResponse;
import com.mark.common.utils.MD5Util;
import com.mark.security.UsernamePasswordToken;
import com.mark.web.sys.common.enmus.UserStateEnum;
import com.mark.web.sys.entity.from.UserFrom;
import com.mark.web.sys.entity.po.User;
import com.mark.web.sys.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Description : 注册登录相关的控制器
 * @Author : Mark
 * @CreateDate : 2019/1/1 20:23
 * @Version : 2.0
 * @Copyright : 豆浆油条个人非正式工作室
 * 注：该类下的接口不经过shrio的登录验证
 */
@Api(tags = "系统-用户注册登录模块")
@RestController
@RequestMapping(value = "/sys/user/registerLogin/")
public class UserRegisterLoginController {

    private final IUserService iUserService;

    public UserRegisterLoginController(IUserService iUserService) {
        this.iUserService = iUserService;
    }

    @ApiOperation(value = "用户登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type",value = "类型",required = true,dataType="String",defaultValue = "username"),
            @ApiImplicitParam(name = "typeValue",value = "类型值",required = true,dataType="String",defaultValue = "mark"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,dataType = "String",defaultValue = "7561669dong")
    })
    @PostMapping(value = "login.do")
    public ServerResponse<String> login(String type,String typeValue,String password){
        //数据校验
        if (StringUtils.isBlank(typeValue) || StringUtils.isBlank(password)) {
            return ServerResponse.createByIllegalArgument("输入的字段不能空！");
        }
        if(!UserStateEnum.getTypes().contains(type)){
            return ServerResponse.createByIllegalArgument("选择的登录类型不正确！");
        }

        //用户登录:执行Realm的doGetAuthenticationInfo()方法进行认证
        password = MD5Util.md5EncodeUtf8(password);
        UsernamePasswordToken token = new UsernamePasswordToken(type,typeValue,password);
        Subject subject = SecurityUtils.getSubject();
        try{
            subject.login(token);
        } catch (AuthenticationException e) {
            return ServerResponse.createByErrorMessage(e.getMessage());
        }
        return ServerResponse.createBySuccessMessage("登录成功");
    }


    @ApiOperation(value = "用户快速注册")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username",value = "用户名",required = true,dataType="String"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,dataType="String")
    })
    @PostMapping(value = "register_quick.do")
    public ServerResponse<Map<String, Object>>  registerSimple(String username, String password){
        //数据校验
        if(StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            return ServerResponse.createByIllegalArgument("输入的用户名、密码不能为空！");
        }

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        return iUserService.registerSimple(user);
    }

    /**
     * 用户注册
     *
     * @param userFrom ：用户对象信息表单
     * @param bindingResult ：表单的验证结果
     * @return ：用户注册的结果
     *
     * 注册时userFrom中接受的参数有以下
     * <p>
     *    --------------------------------------------------------
     * / 参数名    /类型     /是否必填          / 说明         /
     * -----------------------------------------------------
     *  username   string    true              用户名
     *  password   string    true              密码
     *  email      string    true              邮箱
     *  phone      string    true              电话
     *  question   string    false             问题
     *  answer     string    false             答案
     *  gender     string    false             性别
     * <p/>
     */
    @ApiOperation(value = "用户注册")
    @PostMapping(value = "register.do")
    public ServerResponse<Map<String, Object>>  register(@Valid UserFrom userFrom, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ServerResponse.createByErrorMessage(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        User user = new User();
        BeanUtils.copyProperties(userFrom, user);
        //用户性别的校验
        if(StringUtils.isNotBlank(userFrom.getGender())){
            List<String> userGenderTypeList = UserStateEnum.getUserGenderTypes();
            if(userGenderTypeList.contains(userFrom.getGender())){
                UserStateEnum userGenderEnum = UserStateEnum.stateInfoOf(userFrom.getGender());
                if(userGenderEnum == null){
                    return ServerResponse.createByIllegalArgument("输入的性别值不合法！");
                }else{
                    int gender = userGenderEnum.getState();
                    user.setGender((short) gender);
                }
            }else{
                return ServerResponse.createByIllegalArgument("输入的性别值不合法！");
            }
        }
        return iUserService.register(user);
    }

    /**
     * 用户退出登录，用户提出登录请求已经在ShrioRealm配置，实际上请求不会达到该方法
     * 添加该接口是为了方便在SwaggerUI界面测试退出。
     * @return ：
     */
    @ApiOperation(value = "用户退出登录")
    @GetMapping(value = "logout.do")
    public ServerResponse<String> logout(){
        return ServerResponse.createBySuccess();
    }

    /**
     * 校验输入的用户名、邮箱、手机号码校验
     *
     * @param value ： 校验的值
     * @param type ： 类型
     * @return ： 校验的结果
     */
    @ApiOperation(value = "用户名、邮箱、手机号码的校验")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "value",value = "待校验的字段",required = true,dataType = "String",defaultValue = "mark"),
            @ApiImplicitParam(name = "type",value = "校验字段的类型(username,email,phone)",required = true,dataType = "String",defaultValue = "username")
    })
    @GetMapping(value = "check_valid.do")
    public ServerResponse<String> checkValid(String value,String type){
        //参数校验
        if (StringUtils.isBlank(type)) {
            return ServerResponse.createByIllegalArgument("输入的校验参数值不能为空！");
        }
        List<String> typeList = UserStateEnum.getTypes();
        if(!typeList.contains(type)){
            return ServerResponse.createByIllegalArgument("输入校验类型不正确！");
        }
        return iUserService.checkValid(value, type);
    }

    /**
     * 忘记密码时根据用户名找到问题
     *
     * @param username ：用户名
     * @return ：获取用户名的结果
     */
    @ApiOperation(value = "忘记密码 step1 获取问题")
    @ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "String")
    @PostMapping(value = "forget_get_question.do")
    public ServerResponse<String> forgetGetQuestion(String username) {
        if (StringUtils.isBlank(username)) {
            return ServerResponse.createByIllegalArgument("输入的用户名不能为空");
        }
        return iUserService.selectQuestion(username);
    }

    /**
     * 忘记密码时检查回答问题的答案
     *
     * @param username ： 用户名
     * @param question ： 问题
     * @param answer ： 回答问题的答案
     * @return ：回答正确返回token，错误返回地提示信息
     */
    @ApiOperation(value = "忘记密码 step2 回答问题")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "String"),
            @ApiImplicitParam(name = "question",value = "问题",required = true,dataType = "String"),
            @ApiImplicitParam(name = "answer" ,value = "答案",required = true,dataType = "String")
    })
    @PostMapping(value = "forget_check_answer.do")
    public ServerResponse<String> forgetCheckAnswer(String username, String question, String answer) {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(question) || StringUtils.isBlank(answer)) {
            return ServerResponse.createByIllegalArgument("输入的信息不能为空");
        }
        return iUserService.checkAnswer(username, question, answer);
    }

    /**
     * 忘记密码时更新 新密码
     *
     * @param username ：用户名
     * @param passwordNew ： 新密码
     * @param forgetToken ： token
     * @return ：重置密码结果
     */
    @ApiOperation(value = "忘记密码 step3 重置密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "String"),
            @ApiImplicitParam(name = "passwordNew",value = "新密码",required = true,dataType = "String"),
            @ApiImplicitParam(name = "forgetToken" ,value = "token",required = true,dataType = "String")
    })
    @PostMapping(value = "forget_reset_password.do")
    public ServerResponse<String> forgetRestPassword(String username, String passwordNew, String forgetToken) {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(passwordNew)) {
            return ServerResponse.createByIllegalArgument("输入的信息不能为空");
        }
        if (StringUtils.isBlank(forgetToken)) {
            return ServerResponse.createByException("Token 信息为空");
        }
        return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
    }

    /**
     * 未登录
     * @return ：返回未登录的提示信息
     */
    @GetMapping(value = "unLogin.do")
    public ServerResponse unLogin(HttpServletResponse response){
        // 允许指定域访问跨域资源
        response.setHeader("Access-Control-Allow-Origin", "*");
        return ServerResponse.createByNeedLogin();
    }

}
